import { Cell, Graph, Path } from '@antv/x6';
import { Selection } from '@antv/x6-plugin-selection';
import { Stencil } from '@antv/x6-plugin-stencil';
import { register } from '@antv/x6-react-shape';
import { Col, Row } from 'antd';
import { useEffect, useRef } from 'react';
import './style.less';
const image = {
  logo: 'https://gw.alipayobjects.com/mdn/rms_43231b/afts/img/A*evDjT5vjkX0AAAAAAAAAAAAAARQnAQ',
  success: 'https://gw.alipayobjects.com/mdn/rms_43231b/afts/img/A*6l60T6h8TTQAAAAAAAAAAAAAARQnAQ',
  failed: 'https://gw.alipayobjects.com/mdn/rms_43231b/afts/img/A*SEISQ6My-HoAAAAAAAAAAAAAARQnAQ',
  running: 'https://gw.alipayobjects.com/mdn/rms_43231b/afts/img/A*t8fURKfgSOgAAAAAAAAAAAAAARQnAQ',
};
// #region 初始化图形
const ports = {
  groups: {
    top: {
      position: 'top',
      attrs: {
        circle: {
          r: 4,
          magnet: true,
          stroke: '#5F95FF',
          strokeWidth: 1,
          fill: '#fff',
          style: {
            visibility: 'hidden',
          },
        },
      },
    },
    right: {
      position: 'right',
      attrs: {
        circle: {
          r: 4,
          magnet: true,
          stroke: '#5F95FF',
          strokeWidth: 1,
          fill: '#fff',
          style: {
            visibility: 'hidden',
          },
        },
      },
    },
    bottom: {
      position: 'bottom',
      attrs: {
        circle: {
          r: 4,
          magnet: true,
          stroke: '#5F95FF',
          strokeWidth: 1,
          fill: '#fff',
          style: {
            visibility: 'hidden',
          },
        },
      },
    },
    left: {
      position: 'left',
      attrs: {
        circle: {
          r: 4,
          magnet: true,
          stroke: '#5F95FF',
          strokeWidth: 1,
          fill: '#fff',
          style: {
            visibility: 'hidden',
          },
        },
      },
    },
  },
  items: [
    {
      group: 'top',
    },
    {
      group: 'right',
    },
    {
      group: 'bottom',
    },
    {
      group: 'left',
    },
  ],
};

const AlgoNode = (props: any) => {
  const { node } = props;
  const data = node?.getData() as NodeStatus;
  const { label, status = 'default' } = data;
  return (
    <div className={`node ${status}`}>
      <img src={image.logo} alt="logo" />
      <span className="label">{label}</span>
      <span className="status">
        {status === 'success' && <img src={image.success} alt="success" />}
        {status === 'failed' && <img src={image.failed} alt="failed" />}
        {status === 'running' && <img src={image.running} alt="running" />}
      </span>
    </div>
  );
};
interface NodeStatus {
  id: string;
  status: 'default' | 'success' | 'failed' | 'running';
  label?: string;
}

register({
  shape: 'dag-node',
  width: 180,
  height: 36,
  component: AlgoNode,
  ports: {
    groups: {
      top: {
        position: 'top',
        attrs: {
          circle: {
            r: 4,
            magnet: true,
            stroke: '#C2C8D5',
            strokeWidth: 1,
            fill: '#fff',
          },
        },
      },
      bottom: {
        position: 'bottom',
        attrs: {
          circle: {
            r: 4,
            magnet: true,
            stroke: '#C2C8D5',
            strokeWidth: 1,
            fill: '#fff',
          },
        },
      },
    },
  },
});
Graph.registerNode(
  'custom-rect',
  {
    inherit: 'rect',
    width: 126,
    height: 36,

    attrs: {
      body: {
        strokeWidth: 1,
        stroke: '#5F95FF',
        fill: '#EFF4FF',
      },
      text: {
        fontSize: 12,
        fill: '#262626',
      },
    },
    ports: { ...ports },
  },
  true,
);

Graph.registerEdge(
  'dag-edge',
  {
    inherit: 'edge',
    attrs: {
      line: {
        stroke: '#C2C8D5',
        strokeWidth: 1,
        targetMarker: null,
      },
    },
  },
  true,
);

Graph.registerConnector(
  'algo-connector',
  (s, e) => {
    const offset = 4;
    const deltaY = Math.abs(e.y - s.y);
    const control = Math.floor((deltaY / 3) * 2);

    const v1 = { x: s.x, y: s.y + offset + control };
    const v2 = { x: e.x, y: e.y - offset - control };

    return Path.normalize(
      `M ${s.x} ${s.y}
         L ${s.x} ${s.y + offset}
         C ${v1.x} ${v1.y} ${v2.x} ${v2.y} ${e.x} ${e.y - offset}
         L ${e.x} ${e.y}
        `,
    );
  },
  true,
);

const nodeStatusList = [
  [
    {
      id: '1',
      status: 'running',
    },
    {
      id: '2',
      status: 'default',
    },
    {
      id: '3',
      status: 'default',
    },
    {
      id: '4',
      status: 'default',
    },
  ],
  [
    {
      id: '1',
      status: 'success',
    },
    {
      id: '2',
      status: 'running',
    },
    {
      id: '3',
      status: 'default',
    },
    {
      id: '4',
      status: 'default',
    },
  ],
  [
    {
      id: '1',
      status: 'success',
    },
    {
      id: '2',
      status: 'success',
    },
    {
      id: '3',
      status: 'running',
    },
    {
      id: '4',
      status: 'running',
    },
  ],
  [
    {
      id: '1',
      status: 'success',
    },
    {
      id: '2',
      status: 'success',
    },
    {
      id: '3',
      status: 'success',
    },
    {
      id: '4',
      status: 'failed',
    },
  ],
];

const X6Graph = () => {
  const containerRef = useRef(null);
  // 这样放置到画布上的节点 ID 和 dnd start 传入的 node ID 一致
  // const dnd = new Dnd({
  //   getDragNode: (node: any) => node.clone({ keepId: true }),
  //   getDropNode: (node: any) => node.clone({ keepId: true }),
  // } as any);
  useEffect(() => {
    // #endregion
    const graph: any = new Graph({
      container: containerRef.current as any,
      panning: {
        enabled: true,
        eventTypes: ['leftMouseDown', 'mouseWheel'],
      },
      mousewheel: {
        enabled: true,
        modifiers: 'ctrl',
        factor: 1.1,
        maxScale: 1.5,
        minScale: 0.5,
      },
      highlighting: {
        magnetAdsorbed: {
          name: 'stroke',
          args: {
            attrs: {
              fill: '#fff',
              stroke: '#31d0c6',
              strokeWidth: 4,
            },
          },
        },
      },
      connecting: {
        snap: false,
        allowBlank: false,
        allowLoop: false,
        highlight: true,
        connector: 'algo-connector',
        connectionPoint: 'anchor',
        anchor: 'center',
        validateMagnet({ magnet }: any) {
          return magnet.getAttribute('port-group') !== 'top';
        },
        createEdge() {
          return graph.createEdge({
            shape: 'dag-edge',
            attrs: {
              line: {
                strokeDasharray: '5 5',
              },
            },
            zIndex: -1,
          });
        },
      },
    } as any);
    graph.use(
      new Selection({
        multiple: true,
        rubberEdge: true,
        rubberNode: true,
        modifiers: 'shift',
        rubberband: true,
      }),
    );
    // #region 初始化 stencil
    const stencil = new Stencil({
      title: '流程图',
      target: graph,
      stencilGraphWidth: 200,
      stencilGraphHeight: 180,
      collapsable: false,
      //   此处返回自定义到画布的节点
      getDropNode: () => {
        return graph.createNode({
          shape: 'dag-node',
          //   x: 290,
          //   y: 110,
          data: {
            label: '工艺11',
            status: 'success',
          },
          ports: [
            {
              id: '1-1',
              group: 'bottom',
            },
          ],
        });
      },
      groups: [
        {
          title: '工序',
          name: 'group1',
        },
      ],
      layoutOptions: {
        columns: 1,
        dx: 50,
        // columnWidth: 80,
        rowHeight: 45,
      },
    });

    // document.getElementById('stencil')!.appendChild(stencil.container);

    const r1 = graph.createNode({
      shape: 'custom-rect',
      label: '开始',
      attrs: {
        body: {
          rx: 20,
          ry: 26,
        },
      },
    });
    const r2 = graph.createNode({
      shape: 'custom-rect',
      label: '结束',
      attrs: {
        body: {
          rx: 20,
          ry: 26,
        },
      },
    });
    stencil.load([r1, r2], 'group1');

    graph.on('edge:connected', ({ edge }: any) => {
      edge.attr({
        line: {
          strokeDasharray: '',
        },
      });
    });

    graph.on('node:change:data', ({ node }: any) => {
      const edges = graph.getIncomingEdges(node);
      const { status } = node.getData() as NodeStatus;
      edges?.forEach((edge: any) => {
        if (status === 'running') {
          edge.attr('line/strokeDasharray', 5);
          edge.attr('line/style/animation', 'running-line 30s infinite linear');
        } else {
          edge.attr('line/strokeDasharray', '');
          edge.attr('line/style/animation', '');
        }
      });
    });

    // 初始化节点/边
    const init = (data: Cell.Metadata[]) => {
      const cells: Cell[] = [];
      data.forEach((item) => {
        if (item.shape === 'dag-node') {
          cells.push(graph.createNode(item));
        } else {
          cells.push(graph.createEdge(item));
        }
      });
      graph.resetCells(cells);
    };

    // 显示节点状态
    const showNodeStatus = async (statusList: any) => {
      const status = statusList.shift();
      status?.forEach((item: any) => {
        const { id, status } = item;
        const node = graph.getCellById(id);
        const data = node.getData() as NodeStatus;
        node.setData({
          ...data,
          status,
        });
      });
      setTimeout(() => {
        showNodeStatus(statusList);
      }, 3000);
    };

    init([
      {
        id: '1',
        shape: 'dag-node',
        x: 290,
        y: 110,
        data: {
          label: '读数据',
          status: 'success',
        },
        ports: [
          {
            id: '1-1',
            group: 'bottom',
          },
        ],
      },
      {
        id: '2',
        shape: 'dag-node',
        x: 290,
        y: 225,
        data: {
          label: '逻辑回归',
          status: 'success',
        },
        ports: [
          {
            id: '2-1',
            group: 'top',
          },
          {
            id: '2-2',
            group: 'bottom',
          },
          {
            id: '2-3',
            group: 'bottom',
          },
        ],
      },
      {
        id: '3',
        shape: 'dag-node',
        x: 170,
        y: 350,
        data: {
          label: '模型预测',
          status: 'success',
        },
        ports: [
          {
            id: '3-1',
            group: 'top',
          },
          {
            id: '3-2',
            group: 'bottom',
          },
        ],
      },
      {
        id: '4',
        shape: 'dag-node',
        x: 450,
        y: 350,
        data: {
          label: '读取参数',
          status: 'success',
        },
        ports: [
          {
            id: '4-1',
            group: 'top',
          },
          {
            id: '4-2',
            group: 'bottom',
          },
        ],
      },
      {
        id: '5',
        shape: 'dag-edge',
        source: {
          cell: '1',
          port: '1-1',
        },
        target: {
          cell: '2',
          port: '2-1',
        },
        zIndex: 0,
      },
      {
        id: '6',
        shape: 'dag-edge',
        source: {
          cell: '2',
          port: '2-2',
        },
        target: {
          cell: '3',
          port: '3-1',
        },
        zIndex: 0,
      },
      {
        id: '7',
        shape: 'dag-edge',
        source: {
          cell: '2',
          port: '2-3',
        },
        target: {
          cell: '4',
          port: '4-1',
        },
        zIndex: 0,
      },
    ]);
    showNodeStatus(nodeStatusList);
    graph.centerContent();

    // return () => {
    //   graph.dispose();
    // };
  }, []);

  return (
    <Row>
      {/* <Col span={5}>
        <div id={'stencil'}></div>
      </Col> */}
      <Col span={24}>
        <div key={113331} ref={containerRef} style={{ width: '100%', height: '400px' }} />
      </Col>
    </Row>
  );
};
// 我们用 insert-css 演示引入自定义样式
// 推荐将样式添加到自己的样式文件中
// 若拷贝官方代码，别忘了 npm install insert-css
export default X6Graph;
